<!-- components/CustomSwiper/CustomSwiper.vue -->
<template>
  <view class="custom-swiper-container">
    <!-- 轮播图主体 -->
    <view 
      class="swiper-wrapper"
      @touchstart="handleTouchStart"
      @touchmove="handleTouchMove"
      @touchend="handleTouchEnd"
      @mousedown="handleMouseDown"
      @mousemove="handleMouseMove"
      @mouseup="handleMouseUp"
      @mouseleave="handleMouseLeave"
    >
      <view 
        class="swiper-items"
        :style="{
          transform: `translateX(${translateX}px)`,
          transition: isSwiping ? 'none' : `transform ${duration}ms ease`
        }"
      >
        <!-- 循环渲染轮播项 -->
        <view 
          v-for="(item, index) in swiperItems" 
          :key="index"
          class="swiper-item"
          :style="{ width: swiperWidth + 'px' }"
        >
          <slot :item="item" :index="index">
            <!-- 默认内容 -->
            <image 
              v-if="item.image" 
              :src="item.image" 
              class="swiper-image"
              mode="aspectFill"
              @click="handleItemClick(index)"
            />
            <view v-if="item.title" class="swiper-title">{{ item.title }}</view>
            <view v-if="item.description" class="swiper-description">{{ item.description }}</view>
          </slot>
        </view>
      </view>
    </view>
    
    <!-- 指示器 -->
    <view 
      v-if="showIndicators" 
      class="swiper-indicators"
      :class="{ 'indicators-outside': indicatorPosition === 'outside' }"
    >
      <view 
        v-for="(item, index) in originalItems" 
        :key="index"
        class="indicator"
        :class="{ 'active': currentIndex === index }"
        @click="switchTo(index)"
      ></view>
    </view>
    
    <!-- 导航箭头 -->
    <view 
      v-if="showArrows && originalItems.length > 1" 
      class="swiper-arrow left-arrow"
      @click="prev"
    >
      <text class="arrow-icon">‹</text>
    </view>
    <view 
      v-if="showArrows && originalItems.length > 1" 
      class="swiper-arrow right-arrow"
      @click="next"
    >
      <text class="arrow-icon">›</text>
    </view>
  </view>
</template>

<script>
export default {
  name: 'CustomSwiper',
  props: {
    // 轮播数据
    items: {
      type: Array,
      default: () => []
    },
    // 是否自动播放
    autoplay: {
      type: Boolean,
      default: true
    },
    // 自动播放间隔（毫秒）
    interval: {
      type: Number,
      default: 3000
    },
    // 切换动画时长（毫秒）
    duration: {
      type: Number,
      default: 300
    },
    // 是否循环播放
    loop: {
      type: Boolean,
      default: true
    },
    // 是否显示指示器
    showIndicators: {
      type: Boolean,
      default: true
    },
    // 指示器位置
    indicatorPosition: {
      type: String,
      default: 'inside', // 'inside' | 'outside'
      validator: value => ['inside', 'outside'].includes(value)
    },
    // 是否显示导航箭头
    showArrows: {
      type: Boolean,
      default: false
    },
    // 是否启用手指滑动
    enableTouch: {
      type: Boolean,
      default: true
    },
    // 初始索引
    initialIndex: {
      type: Number,
      default: 0
    }
  },
  
  data() {
    return {
      currentIndex: this.initialIndex,
      translateX: 0,
      swiperWidth: 375, // 默认宽度
      isSwiping: false,
      touchStartX: 0,
      touchStartY: 0,
      translateStartX: 0,
      autoplayTimer: null,
      isMouseDown: false
    }
  },
  
  computed: {
    // 原始数据
    originalItems() {
      return this.items || []
    },
    
    // 轮播项（包含循环项）
    swiperItems() {
      if (!this.originalItems.length) return []
      
      // 如果只有一项或不循环，直接返回原数组
      if (this.originalItems.length <= 1 || !this.loop) {
        return this.originalItems
      }
      
      // 循环模式：在首尾各添加一项用于无缝循环
      const items = [...this.originalItems]
      items.unshift(this.originalItems[this.originalItems.length - 1]) // 添加最后一项到开头
      items.push(this.originalItems[0]) // 添加第一项到结尾
      return items
    },
    
    // 实际显示的索引（循环模式下需要调整）
    displayIndex() {
      if (!this.loop || this.originalItems.length <= 1) {
        return this.currentIndex
      }
      
      // 循环模式下，实际索引需要减1（因为我们在开头添加了一个元素）
      return this.currentIndex === 0 
        ? this.originalItems.length - 1 
        : this.currentIndex === this.swiperItems.length - 1 
          ? 0 
          : this.currentIndex - 1
    }
  },
  
  mounted() {
    this.initSwiper()
    if (this.autoplay) {
      this.startAutoplay()
    }
  },
  
  beforeDestroy() {
    this.stopAutoplay()
  },
  
  watch: {
    items: {
      handler() {
        this.resetSwiper()
      },
      deep: true
    },
    
    autoplay(newVal) {
      if (newVal) {
        this.startAutoplay()
      } else {
        this.stopAutoplay()
      }
    },
    
    currentIndex(newVal) {
      this.updateTranslateX()
      // 触发change事件
      this.$emit('change', {
        index: this.displayIndex,
        item: this.originalItems[this.displayIndex]
      })
    }
  },
  
  methods: {
    // 初始化轮播图
    initSwiper() {
      this.getSwiperWidth()
      this.updateTranslateX()
    },
    
    // 获取轮播图宽度
    getSwiperWidth() {
      const query = uni.createSelectorQuery().in(this)
      query.select('.custom-swiper-container').boundingClientRect(data => {
        if (data) {
          this.swiperWidth = data.width || 375
          this.updateTranslateX()
        }
      }).exec()
    },
    
    // 更新位移
    updateTranslateX() {
      if (!this.swiperWidth) return
      
      // 计算位移
      const index = this.loop && this.originalItems.length > 1 
        ? this.currentIndex 
        : this.currentIndex
      
      this.translateX = -index * this.swiperWidth
    },
    
    // 重置轮播图
    resetSwiper() {
      this.currentIndex = this.initialIndex
      this.getSwiperWidth()
      this.updateTranslateX()
    },
    
    // 开始自动播放
    startAutoplay() {
      this.stopAutoplay()
      if (this.autoplay && this.originalItems.length > 1) {
        this.autoplayTimer = setInterval(() => {
          this.next()
        }, this.interval)
      }
    },
    
    // 停止自动播放
    stopAutoplay() {
      if (this.autoplayTimer) {
        clearInterval(this.autoplayTimer)
        this.autoplayTimer = null
      }
    },
    
    // 切换到指定索引
    switchTo(index) {
      if (index === this.displayIndex) return
      
      this.stopAutoplay()
      
      if (this.loop && this.originalItems.length > 1) {
        // 循环模式
        if (index === 0 && this.displayIndex === this.originalItems.length - 1) {
          // 从最后一项到第一项
          this.currentIndex = this.swiperItems.length - 1
          setTimeout(() => {
            this.isSwiping = true
            this.currentIndex = 1
            setTimeout(() => {
              this.isSwiping = false
            }, 50)
          }, this.duration)
        } else if (index === this.originalItems.length - 1 && this.displayIndex === 0) {
          // 从第一项到最后一项
          this.currentIndex = 0
          setTimeout(() => {
            this.isSwiping = true
            this.currentIndex = this.originalItems.length
            setTimeout(() => {
              this.isSwiping = false
            }, 50)
          }, this.duration)
        } else {
          // 普通切换
          this.currentIndex = index + 1 // 循环模式下索引需要+1
        }
      } else {
        // 非循环模式
        this.currentIndex = index
      }
      
      if (this.autoplay) {
        this.startAutoplay()
      }
    },
    
    // 下一张
    next() {
      if (this.originalItems.length <= 1) return
      
      this.stopAutoplay()
      
      if (this.loop) {
        // 循环模式
        if (this.currentIndex >= this.swiperItems.length - 1) {
          // 到达末尾，瞬间跳转到开头
          this.isSwiping = true
          this.currentIndex = 1
          setTimeout(() => {
            this.isSwiping = false
          }, 50)
        } else {
          this.currentIndex++
        }
      } else {
        // 非循环模式
        if (this.currentIndex < this.originalItems.length - 1) {
          this.currentIndex++
        } else {
          this.currentIndex = 0
        }
      }
      
      if (this.autoplay) {
        this.startAutoplay()
      }
    },
    
    // 上一张
    prev() {
      if (this.originalItems.length <= 1) return
      
      this.stopAutoplay()
      
      if (this.loop) {
        // 循环模式
        if (this.currentIndex <= 0) {
          // 到达开头，瞬间跳转到末尾
          this.isSwiping = true
          this.currentIndex = this.swiperItems.length - 2
          setTimeout(() => {
            this.isSwiping = false
          }, 50)
        } else {
          this.currentIndex--
        }
      } else {
        // 非循环模式
        if (this.currentIndex > 0) {
          this.currentIndex--
        } else {
          this.currentIndex = this.originalItems.length - 1
        }
      }
      
      if (this.autoplay) {
        this.startAutoplay()
      }
    },
    
    // 处理触摸开始
    handleTouchStart(e) {
      if (!this.enableTouch || this.originalItems.length <= 1) return
      
      this.stopAutoplay()
      this.isSwiping = true
      
      const touch = e.touches ? e.touches[0] : e
      this.touchStartX = touch.clientX
      this.touchStartY = touch.clientY
      this.translateStartX = this.translateX
    },
    
    // 处理触摸移动
    handleTouchMove(e) {
      if (!this.isSwiping || !this.enableTouch || this.originalItems.length <= 1) return
      
      const touch = e.touches ? e.touches[0] : e
      const deltaX = touch.clientX - this.touchStartX
      const deltaY = touch.clientY - this.touchStartY
      
      // 判断是否为水平滑动
      if (Math.abs(deltaX) > Math.abs(deltaY)) {
        e.preventDefault()
        this.translateX = this.translateStartX + deltaX
      }
    },
    
    // 处理触摸结束
    handleTouchEnd() {
      if (!this.isSwiping || this.originalItems.length <= 1) return
      
      this.isSwiping = false
      
      const deltaX = this.translateX - this.translateStartX
      const threshold = this.swiperWidth * 0.3 // 滑动阈值为宽度的30%
      
      if (deltaX > threshold) {
        // 向右滑动，显示上一张
        this.prev()
      } else if (deltaX < -threshold) {
        // 向左滑动，显示下一张
        this.next()
      } else {
        // 未达到阈值，回到原位置
        this.updateTranslateX()
      }
      
      if (this.autoplay) {
        this.startAutoplay()
      }
    },
    
    // 处理鼠标按下
    handleMouseDown(e) {
      this.isMouseDown = true
      this.handleTouchStart(e)
    },
    
    // 处理鼠标移动
    handleMouseMove(e) {
      if (!this.isMouseDown) return
      this.handleTouchMove(e)
    },
    
    // 处理鼠标抬起
    handleMouseUp() {
      if (!this.isMouseDown) return
      this.isMouseDown = false
      this.handleTouchEnd()
    },
    
    // 处理鼠标离开
    handleMouseLeave() {
      if (this.isMouseDown) {
        this.isMouseDown = false
        this.handleTouchEnd()
      }
    },
    
    // 处理轮播项点击
    handleItemClick(index) {
      const actualIndex = this.loop && this.originalItems.length > 1
        ? (index === 0 ? this.originalItems.length - 1 : index === this.swiperItems.length - 1 ? 0 : index - 1)
        : index
      
      this.$emit('click', {
        index: actualIndex,
        item: this.originalItems[actualIndex]
      })
    }
  }
}
</script>

<style scoped>
.custom-swiper-container {
  position: relative;
  width: 100%;
  overflow: hidden;
}

.swiper-wrapper {
  width: 100%;
  height: 100%;
  position: relative;
}

.swiper-items {
  display: flex;
  height: 100%;
  height: 300px;
  width: max-content;
}

.swiper-item {
  flex-shrink: 0;
  height: 100%;
  position: relative;
}

.swiper-image {
  width: 100%;
  height: 100%;
}

.swiper-title {
  position: absolute;
  bottom: 60rpx;
  left: 30rpx;
  right: 30rpx;
  color: #fff;
  font-size: 36rpx;
  font-weight: bold;
  text-shadow: 2rpx 2rpx 4rpx rgba(0, 0, 0, 0.5);
}

.swiper-description {
  position: absolute;
  bottom: 20rpx;
  left: 30rpx;
  right: 30rpx;
  color: #fff;
  font-size: 28rpx;
  text-shadow: 1rpx 1rpx 2rpx rgba(0, 0, 0, 0.5);
}

.swiper-indicators {
  position: absolute;
  bottom: 20rpx;
  left: 50%;
  transform: translateX(-50%);
  display: flex;
  gap: 12rpx;
  z-index: 10;
}

.indicators-outside {
  position: relative;
  bottom: auto;
  left: auto;
  transform: none;
  margin-top: 20rpx;
  justify-content: center;
}

.indicator {
  width: 12rpx;
  height: 12rpx;
  border-radius: 50%;
  background: rgba(255, 255, 255, 0.5);
  transition: all 0.3s;
}

.indicator.active {
  background: #fff;
  transform: scale(1.2);
}

.swiper-arrow {
  position: absolute;
  top: 50%;
  transform: translateY(-50%);
  width: 60rpx;
  height: 60rpx;
  background: rgba(0, 0, 0, 0.3);
  border-radius: 50%;
  display: flex;
  justify-content: center;
  align-items: center;
  z-index: 10;
  cursor: pointer;
  transition: all 0.3s;
}

.swiper-arrow:hover {
  background: rgba(0, 0, 0, 0.5);
}

.left-arrow {
  left: 20rpx;
}

.right-arrow {
  right: 20rpx;
}

.arrow-icon {
  color: #fff;
  font-size: 48rpx;
  font-weight: bold;
  line-height: 1;
}
</style>